import React from 'react';
import {message} from 'antd';
import {Icon} from '../index';

import './index.scss';

/**
 * 图片预览、缩放组件
 * 属性：
 * className：类名。
 * imgShow：图片是否显示。类型：boolean。默认值：false。
 * imgIndex：图片索引。类型：number。默认值：0。
 * imgList：图片列表。类型：string[] | Option[]。
 * onChange：页码改变的回调。类型：Function(index)。
 * onClose：图片退出的回调。类型：Function()。
 */
export class ImgPreview extends React.Component {
  static defaultProps = {
    className: '',
    imgShow: false,
    imgIndex: 0
  };

  constructor(props) {
    super(props);
    this.state = {
      imgScale: 1, //当前预览图片的缩放比例
      left: 0, //预览图片的水平偏移
      top: 0 //预览图片的垂直偏移
    };
  }

  componentDidMount() {
    this.bindMove();
  }

  render() {
    let {className, imgShow} = this.props;
    return (
      <div className={`g-img-preview ${className}`} style={{display: imgShow ? '' : 'none'}}>
        {this.renderIcon(0)}
        {this.renderPreviewCenter()}
        {this.renderIcon(1)}
      </div>
    );
  }

  /**
   * 预览：中间部分，包含预览图片、缩放按钮、下标
   */
  renderPreviewCenter() {
    let {imgScale, left, top} = this.state;
    let {imgIndex, imgList} = this.props;
    //由于bindMove()在页面加载完成时，会对gBox进行处理，所以需要给imgList设置默认值。
    imgList = imgList || [];

    let img = imgList[imgIndex];
    let propsImg = {
      className: 'outer-img',
      ref: (r) => (this.gBoxImg = r),
      src: (img && img.url) || img,
      style: {left, top, transform: `scale(${imgScale})`}
    };
    return (
      <div className="center">
        <div className="outer" ref={(r) => (this.gBox = r)}>
          <img {...propsImg} />
          <Icon className="outer-exit" type="close" onClick={this.onClose} />
        </div>
        <div className="control">
          <Icon className="control-icon" type="plus" onClick={this.onPlusClick} />
          <Icon className="control-icon" type="minus" onClick={this.onMinusClick} />
          <Icon className="control-icon" type="reload" onClick={this.onReload} />
          <Icon className="control-icon" type="fullscreen" onClick={this.onFullScreen} />
          <span className="control-num">{imgIndex + 1}</span>
          <span className="control-num">/</span>
          <span className="control-num">{imgList.length || 1}</span>
        </div>
      </div>
    );
  }

  /**
   * 展示两边图标
   * @param type 0表示左侧图标，1表示右侧图标
   */
  renderIcon(type) {
    let {imgList} = this.props;
    if (!imgList || imgList.length < 2) {
      return;
    }

    let props = {
      className: 'icon',
      type: type == 0 ? 'left' : 'right',
      theme: 'outlined',
      onClick: () => this.onChange(type)
    };
    return <Icon {...props} />;
  }

  /**
   * 图片关闭的回调
   */
  onClose = () => {
    let {onClose} = this.props;
    onClose && onClose();
    this.setState({imgScale: 1, left: 0, top: 0});
  };

  /**
   * 页码改变的回调
   * @param type 0表示左侧图标，1表示右侧图标
   */
  onChange = (type) => {
    let {imgIndex, imgList, onChange} = this.props;
    let index = type == 0 ? imgIndex - 1 : imgIndex + 1;
    if (index < 0) {
      message.info('已到第一页');
      return;
    } else if (index >= imgList.length) {
      message.info('已到最后一页');
      return;
    }
    onChange && onChange(index, imgList.length);
    this.setState({imgScale: 1, left: 0, top: 0});
  };

  /**
   * 图片放大事件
   */
  onPlusClick = (e) => {
    let {imgScale} = this.state;
    imgScale = imgScale + 0.3;
    //最大放大比例为5；
    imgScale = imgScale > 5 ? 5 : imgScale;
    this.setState({imgScale});
  };

  /**
   * 图片缩小事件
   */
  onMinusClick = () => {
    let {imgScale} = this.state;
    imgScale = imgScale - 0.3;
    //最小缩小比例为1；
    imgScale = imgScale < 0.2 ? 0.2 : imgScale;
    this.setState({imgScale});
  };

  /**
   * 图片还原事件
   */
  onReload = () => {
    this.setState({imgScale: 1, left: 0, top: 0});
  };

  /**
   * 全屏展示的回调
   * @param e
   */
  onFullScreen = (e) => {
    //是否全屏状态
    let isFull = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
    let el = this.gBoxImg;

    if (!isFull) {
      //进入全屏的方法：兼容多个浏览器
      let enterScreen = el.requestFullscreen || el.mozRequestFullScreen || el.webkitRequestFullscreen;
      enterScreen.call(el);
    } else {
      //退出全屏的方法：兼容多个浏览器
      let exitScreen = document.exitFullscreen || document.mozCancelFullScreen || document.webkitExitFullscreen;
      //注意：exitFullscreen必须由document调用
      exitScreen.call(document);
    }
  };

  /**
   * 绑定鼠标拖动事件
   */
  bindMove = () => {
    //图片的容器
    let gBox = this.gBox;
    //需要移动的图片
    let gBoxImg = this.gBoxImg;
    gBoxImg.onmousedown = (ev) => {
      // 浏览器有一些图片的默认事件,这里要阻止
      ev.preventDefault();

      let {left, top} = this.state;
      let rect1 = gBox.getBoundingClientRect(); //获取元素大小和相对视口的位置
      let rect2 = gBoxImg.getBoundingClientRect();
      let x = left; //初始的水平偏移
      let y = top; //初始的垂直偏移
      let lengthL = rect1.left - rect2.left; //左偏移
      let lengthR = rect1.right - rect2.right; //右偏移
      let lengthT = rect1.top - rect2.top; //上偏移
      let lengthB = rect1.bottom - rect2.bottom; //下偏移

      gBoxImg.onmousemove = (ev2) => {
        ev2.preventDefault();

        //clientX、clientY：点击位置距离当前body可视区域的x，y坐标
        let x1 = ev2.clientX - ev.clientX;
        let y1 = ev2.clientY - ev.clientY;
        //计算边界
        if (x1 < 0) {
          if (lengthR < 0) {
            x1 = x1 < lengthR ? lengthR : x1;
          } else if (lengthL < 0) {
            x1 = x1 < lengthL ? lengthL : x1;
          } else {
            x1 = 0;
          }
        } else {
          if (lengthL > 0) {
            x1 = x1 > lengthL ? lengthL : x1;
          } else if (lengthR > 0) {
            x1 = x1 > lengthR ? lengthR : x1;
          } else {
            x1 = 0;
          }
        }
        if (y1 < 0) {
          if (lengthB < 0) {
            y1 = y1 < lengthB ? lengthB : y1;
          } else if (lengthT < 0) {
            y1 = y1 < lengthT ? lengthT : y1;
          } else {
            y1 = 0;
          }
        } else {
          if (lengthT > 0) {
            y1 = y1 > lengthT ? lengthT : y1;
          } else if (lengthB > 0) {
            y1 = y1 > lengthB ? lengthB : y1;
          } else {
            y1 = 0;
          }
        }

        left = x + x1;
        top = y + y1;
        this.setState({left, top});
      };
    };
    // 图形移出父盒子取消移动事件,防止移动过快触发鼠标移出事件,导致鼠标弹起事件失效
    gBoxImg.onmouseleave = () => {
      gBoxImg.onmousemove = null;
    };
    // 鼠标弹起后停止移动
    gBoxImg.onmouseup = () => {
      gBoxImg.onmousemove = null;
    };
  };
}

/**
 * 图片展示、预览、缩放组件
 * 属性：
 * className：类名。
 * src：图片地址。类型：string。
 * alt：占位符。类型：string。默认值：图片。
 * imgList：预览图片地址。类型：[{url}]
 */
export default class Img extends React.Component {
  static defaultProps = {
    className: '',
    alt: '图片'
  };

  constructor(props) {
    super(props);
    this.state = {
      previewShow: false, //是否显示预览页
      previewIndex: 0 //当前预览页索引，最小值为0
    };
  }

  render() {
    let {previewShow, previewIndex} = this.state;
    let {className, style, src, imgList = [{url: src}]} = this.props;
    return (
      <div className={`g-img ${className}`} style={style}>
        {this.renderImg()}
        <ImgPreview
          imgShow={previewShow}
          imgIndex={previewIndex}
          imgList={imgList}
          onClose={this.onClose}
          onChange={this.onChange}
        />
      </div>
    );
  }

  /**
   * 展示图片
   */
  renderImg() {
    let {src, alt} = this.props;
    let props = {className: 'item-img', src, alt};
    return (
      <div className="item">
        <img {...props} />
        <div className="item-up" onClick={this.onImgClick}>
          <Icon className="item-up-icon" type="eye-o" />
        </div>
      </div>
    );
  }

  /**
   * 图片点击事件
   */
  onImgClick = () => {
    let {src, imgList} = this.props;
    let previewIndex = 0;
    if (imgList && imgList.length > 0) {
      previewIndex = imgList.findIndex((item) => item.url === src);
    }
    this.setState({previewShow: true, previewIndex});
  };

  /**
   * 图片关闭的回调
   */
  onClose = () => {
    this.setState({previewShow: false});
  };

  /**
   * 页码改变的回调
   * @param index 改变后的页码
   * @param size 总页数
   */
  onChange = (index, size) => {
    this.setState({previewIndex: index});
  };
}
